/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/*!
  \file			pgsxml.h
  \date			Feb 2012
  \author		TNick

  \brief		Contains the definition for PgsXml class


*//*


 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Please read COPYING and README files in root folder
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
#ifndef __PGSXML_INC__
#define __PGSXML_INC__
//
//
//
//
/*  INCLUDES    ------------------------------------------------------------ */

#ifdef	USE_PGSAVE_INTERFACE
#include	"ipgsave.h"
#endif

#include	<QDomDocument>

/*  INCLUDES    ============================================================ */
//
//
//
//
/*  CLASS    --------------------------------------------------------------- */

namespace PgSave		{

/**
	@brief	Offers a consistent way of saving things using XML files

	The class may be used as it is, without \b USE_PGSAVE_INTERFACE defined, or
	as a class exposing the IPgSave interface otherwise. The only major
	difference is that some methods are virtual when used with
	\b USE_PGSAVE_INTERFACE.
*/
class PgsXml
		#ifdef	USE_PGSAVE_INTERFACE
		:	public	IPgSave
		#endif
{
	//
	//
	//
	//
	/*  DEFINITIONS    ----------------------------------------------------- */

#ifdef	PGSAVE_TESTS
	friend void		PgsXml_Tests	( int&, int& );
#endif

#define PQXML_TRUE	"TRUE"
#define PQXML_FALSE	"FALSE"

#define	PQXML_INT	"integer"
#define	PQXML_DBL	"double"
#define	PQXML_BOOL	"bool"
#define	PQXML_STR	"string"
#define	PQXML_COLOR	"color"
#define	PQXML_CHAR	"char"


	/*  DEFINITIONS    ===================================================== */
	//
	//
	//
	//
	/*  DATA    ------------------------------------------------------------ */

private:

	/**
	*	@brief	the embedded document
	*/
	QDomDocument	doc;


	/**
	*	@brief	current path
	*/
	QDomElement		crt_p_;


	/*  DATA    ============================================================ */
	//
	//
	//
	//
	/*  FUNCTIONS    ------------------------------------------------------- */

public:


	/**
	*	@brief	constructor;
	*/
	PgsXml			( void );


	/**
	*	@brief	destructor;
	*/
	virtual				~PgsXml		( void );

	/**
	*	@brief	changes the current path in this instance
	*
	*	The path may be changed to an absolute path or provided path
	*	may be appended to current path. If the path starts with a "/" then
	*	the path is absolute, otherwise is relative.
	*
	*	Paths are sepparated by a "/" character despite the opperating system
	*	settings regardng paths.
	*
	*	@param	new_crt	string representing new path
	*/
	bool		setPath			(
			const QString			new_crt
			);


	/**
	*	@brief	retrieve current path as a list of names sepparated by "/"
	*/
	QString		path			( void );


	/**
	*	@brief	retrieve current path as a list of strings
	*
	*	@param	sl_out list where the names are appended; it is not cleared;
	*/
	void		path			( QStringList & sl_out );


	/**
	*	@brief	walks up specified number of steps in the path
	*
	*	If the path is already at the root nothing happens. If the number of
	*	steps are larger than the number of steps to the root the root is set.
	*/
	void		cdUp			( unsigned steps = 1 );


	/**
	*	@brief	tells if the path exists or not
	*
	*	If the path starts with a "/" then the path is absolute,
	*	otherwise is relative.
	*
	*	The method will return false for paths that are only folders
	*	without holding an actual value.
	*
	*	@param	s_path	string representing the path to test
	*/
	bool		exists			( QString s_path );


	/**
	*	@brief	iterates the values in current path
	*
	*	The method uses the callback list to find the proper one to call.
	*	If there is no callback for a particular type the default callback
	*	provided as an argument will be used, except if it is NULL, when they
	*	simply ignored.
	*
	*/
	 void		blindLoad		(
			 KB_BLIND_LOAD			kb_default = NULL,
			 void *					kb_data = NULL
			 );


	 /**
	 *	@brief	iterates the provided strings and loads the ones it finds
	 *
	 *	The method uses the callback list to find the proper one to call.
	 *	If there is no callback for a particular type the default callback
	 *	provided as an argument will be used, except if it is NULL, when they
	 *	simply ignored.
	 *
	 */
	  void		blindLoad		(
			  QStringList			load_list,
			  KB_BLIND_LOAD			kb_default = NULL,
			  void *				kb_data = NULL
			  );


	/** @name Retrieving common values
	*
	*/
	//@{

	bool			getBool		(
			QString		s_name,
			bool *		b_ok
			);

	qint16			getShort		(
			QString		s_name,
			bool *		b_ok
			);

	qint32			getInt		(
			QString		s_name,
			bool *		b_ok
			);

	qint64			getLong		(
			QString		s_name,
			bool *		b_ok
			);

	qint8			getByte		(
			QString		s_name,
			bool *		b_ok
			);

	QColor			getColor	(
			QString		s_name,
			bool *		b_ok
			);

	qreal			getDouble	(
			QString		s_name,
			bool *		b_ok
			);

	QStringList		getStrLst	(
			QString		s_name,
			bool *		b_ok
			);

	QString			getStr		(
			QString		s_name,
			bool *		b_ok
			);

	//@}


	//@{
	//!	change the value of the variable; this is a top level method
	//!
	//!	The methods call the validators if present and informs the callbacks

	bool		set		(
			QString			s_name,
			const qint64	new_val
			);

	bool		set		(
			QString			s_name,
			const int		new_val
			);

	bool		set		(
			QString			s_name,
			const bool		new_val
			);

	bool		set		(
			QString			s_name,
			const char		new_val
			);

	bool		set		(
			QString			s_name,
			const QRgb		new_val
			);

	bool		set		(
			QString			s_name,
			const QColor	new_val
			);

	bool		set		(
			QString			s_name,
			const QString	new_val
			);

	bool		set		(
			QString			s_name,
			const char *	new_val
			);

	bool		set		(
			QString			s_name,
			const qreal		new_val
			);

	//@}




	/* ----------------------------------------------- */
	/* methods below this line are not part of IPgSave */
	/* ----------------------------------------------- */

private:

	/**
	*	@brief	performs a blind load on selected node
	*/
	bool				internalBlindLoad	(
			QDomElement		targ_el,
			KB_BLIND_LOAD	kb_default,
			void *			kb_data
			);

	/**
	*	@brief	retrieves the value
	*/
	QString				internalGetVarStr	(
			const QString &	s_name,
			bool *			b_ok
			);


public:

	/**
	*	@brief	allows direct access to document inside
	*/
	inline QDomDocument *		document		( void )
	{ return &doc; }


	/**
	*	@brief	allows direct access to current element
	*/
	inline QDomElement *		currentEl		( void )
	{ return &crt_p_; }


	/**
	*	@brief	saves the document to specified file
	*
	*	The file is overwritten if it exists
	*/
	bool				saveToFile			(
			QString s_path
			);


	/**
	*	@brief	returns a string representing the content of the document
	*/
	inline QString		saveToString			( void )
	{ return doc.toString( 4 ); }


	/**
	*	@brief	makes shure that the path exists
	*
	*	The path is relative to base
	*/
	QDomElement			enshurePath			(
			QDomElement &		base,
			const QString &		s_name
			);

	/**
	*	@brief	makes shure that the path exists
	*
	*	The path is relative to base
	*/
	QDomElement			enshurePath			(
			QDomElement &		base,
			const QStringList &	s_lst
			);

	/**
	*	@brief	makes shure that the path exists
	*
	*	The path is an absolute path and does not take into account
	*	current element
	*/
	QDomElement			enshurePath			(
			const QString &		s_name
			);


	/**
	*	@brief	makes shure that the path exists
	*
	*	The path is an absolute path and does not take into account
	*	current element
	*/
	QDomElement			enshurePath			(
			const QStringList &		s_lst
			);


	/**
	*	@brief	saves a value to a path
	*
	*	The element is set in \b trg_el so that the caller may further
	*	adjust it.
	*
	*/
	QDomElement			enshureVar	(
			const QString &		s_name,
			const QString &		s_type,
			const QString &		s_val
			);


	/**
	*	@brief	gets the element at specified path
	*
	*	The method only recognise Elements as valid nodes; if an node exists
	*	with specified name across the path but is not an element the result
	*	will be false.
	*
	*	@param	base	The path is relative to this element
	*	@param	s_path	Components of the path are separated by a slash (/)
	*	characters; the path may or may not start with a slash and it may or
	*	may not end with a slash; two or more consecutive delimiters are
	*	treated as one
	*	@param	out_e	The element that is set if the path is found
	*
	*	@return	true if the path was found or false otherwise
	*/
	static bool			getElementByPath	(
			const QDomElement &		base,
			const QString &			s_path,
			QDomElement &			out_e
			);

	/**
	*	@brief	gets the element at specified path
	*/
	inline static bool	getElementByPath	(
			QString					s_path,
			const QDomElement &		base,
			QDomElement &			out_e)
	{ return getElementByPath( base, s_path, out_e ); }


	/**
	*	@brief	gets the path of an element
	*/
	static QString		elPath				(
			const QDomElement &		base
			);

	/**
	*	@brief	gets the path of an element
	*/
	static void			elPath				(
			const QDomElement &		base,
			QStringList &			sl
			);



	/**
	*	@brief	creates a new instance and read the content of
	*	provided file
	*/
	static PgsXml *		createFromFile		(
			QString								s_path
			);


	/**
	*	@brief	creates a new instance and read the content of
	*	provided file
	*/
	static PgsXml *		createFromFile		(
			QString								s_path,
			QMap<QString, KB_BLIND_LOAD>	&	other_map
			);


	/**
	*	@brief	creates a new instance
	*
	*	the \b s_root is created and made current
	*/
	static PgsXml *		createNew		(
			QString								s_root
			);


	/**
	*	@brief	creates a new instance
	*
	*	the \b s_root is created and made current
	*/
	static PgsXml *		createNew		(
			QString								s_root,
			QMap<QString, KB_BLIND_LOAD>	&	other_map
			);







	/*  FUNCTIONS    ======================================================= */
	//
	//
	//
	//

};	/*	class PgsXml	*/

/*  CLASS    =============================================================== */
//
//
//
//

#ifdef	PGSAVE_TESTS
	void		PgsXml_Tests	( int&, int& );
#endif
}	//	namespace PgSave

#endif // __PGSXML_INC__
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
